/**
* @author Lourdes Sanchez
* @author Eugenia Jose
* @author Esteban Castro
* @author Carlos Fernandez
* @author Fernando Turon
* @version 1.0 01-05-12
*
* La clase GestorInscripcion se instancia en distintas parte de la aplicación
*
* @see ....
*/

package edu.uoc.tds.pec4.server.bbdd;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.swing.JOptionPane;
import java.rmi.RemoteException;

import edu.uoc.tds.pec4.common.RemotoInterface;
import edu.uoc.tds.pec4.i18n.GestorIdiomas;
import edu.uoc.tds.pec4.model.Estudiante;
import edu.uoc.tds.pec4.model.Prueba;
import edu.uoc.tds.pec4.model.Ronda;
import edu.uoc.tds.pec4.model.TipoEstado;
import edu.uoc.tds.pec4.model.TipoRonda;
import edu.uoc.tds.pec4.model.Usuario;

/**
 *
 * @author Fernando
 */
public class GestorInscripcionRonda {
    //Fernando
    //Atributo de clase para almacenar el remoto
    private RemotoInterface remoto;
    String schema;

    //Fernando
    public GestorInscripcionRonda(RemotoInterface remoto) throws RemoteException{
        this.remoto = remoto;
        this.schema = this.remoto.getSchema();
    }

    //Fernando
    /**
     * Metodo para obtener una lista de instancias de Prueba
     * {pre: es un metodo tÃ­pico de retorno}
     * {post: una lista de instancias de Resultados}
     */
    public void ordenarInscripcionRondaPorPuntuacionYFecha(Prueba prueba, TipoRonda tipoRonda){
	//Establecemos la sentencia para obtener una lista de resultados
        List<Ronda> lista = new ArrayList<Ronda>();

	String sqlString = null;
	sqlString = "SELECT * "
                + "FROM "
                + this.schema + "."
                + "inscripcionronda "
                + "WHERE "
                + "id_prueba = ? "
                + "AND "
                + "id_tipo_ronda = ? "
                + "ORDER BY "
                + "puntuacion DESC, "
                + "Fecha_presentacion ASC;";

        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

	//Capturaremos la excepcion en caso de error
        try{
            preparedStatement = this.remoto.getConexion().prepareStatement(sqlString);
            preparedStatement.setInt(1, prueba.getId_prueba());
            preparedStatement.setInt(2, tipoRonda.valor());

            resultSet = preparedStatement.executeQuery();

            //Si la consulta devuelve un dato generaremos la instancia correspondiente que devolvera el metodo
            Integer posicion = 0;
            //Recorremos el resultset
            while(resultSet.next()){
                int id_prueba;
                int id_tipoRonda;
                int id_usuario;

                id_prueba = resultSet.getInt("id_prueba");
                id_tipoRonda = resultSet.getInt("id_tipo_ronda");
                id_usuario = resultSet.getInt("id_usuario");

                //Actualizamos la clasificacion para un usuaro en una ronda
                this.actualizarPuntuacionInscripcionRonda(id_prueba, id_tipoRonda, id_usuario, ++posicion);
            }
        }

        /** Capturamos el error en el acceso a la BBDD */
        catch (SQLException exc) {
            exc.printStackTrace();
            JOptionPane.showMessageDialog(null, GestorIdiomas.getMessage("gestorinscripcion.errorBBDD"), GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
        }

        /** Capturamos excepcion de caracter general*/
        catch (Exception exc) {
            exc.printStackTrace();
            JOptionPane.showMessageDialog(null, GestorIdiomas.getMessage("gestorinscripcion.error"), GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
            //JOptionPane.showMessageDialog(null, GestorIdiomas.getMessage("error.general"), GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
        }

        /** En todo caso ejecutamos el siguiente codigo*/
        finally {
            try {
                //Cerramos las estructuras abierta
		resultSet.close();
                preparedStatement.close();
            }

            /** Capturamos excepcion de caracter general*/
            catch (Exception exc) {
                JOptionPane.showMessageDialog(null, exc.getMessage(), GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
                //JOptionPane.showMessageDialog(null, GestorIdiomas.getMessage("error.general"), GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    //Fernando
    //Metodo para actualizar la clasificacion de un estudiante en una ronda
    private void actualizarPuntuacionInscripcionRonda(int id_prueba, int id_tipoRonda, int id_usuario, double posicion){
        //Establecemos la sentencia para obtener una lista de resultados
	String sqlString = null;
	sqlString = "UPDATE "
                + this.schema + "."
                + "inscripcionronda "
                + "SET "
                + "clasificacion = ? "
                + "WHERE "
                + "id_prueba = ? "
                + "AND "
                + "id_tipo_ronda = ? "
                + "AND "
                + "id_usuario = ?;";

        PreparedStatement preparedStatement = null;

	//Capturaremos la excepcion en caso de error
        try{
            preparedStatement = this.remoto.getConexion().prepareStatement(sqlString);
            preparedStatement.setDouble(1, posicion);
            preparedStatement.setInt(2, id_prueba);
            preparedStatement.setInt(3, id_tipoRonda);
            preparedStatement.setInt(4, id_usuario);

            preparedStatement.executeUpdate();
        }

        /** Capturamos el error en el acceso a la BBDD */
        catch (SQLException exc) {
            exc.printStackTrace();
            JOptionPane.showMessageDialog(null, GestorIdiomas.getMessage("gestorinscripcion.errorBBDD"), GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
        }

        /** Capturamos excepcion de caracter general*/
        catch (Exception exc) {
            exc.printStackTrace();
            JOptionPane.showMessageDialog(null, GestorIdiomas.getMessage("gestorinscripcion.error"), GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
        }

        /** En todo caso ejecutamos el siguiente codigo*/
        finally {
            //Cerramos las estructuras abiertas
            try {
                preparedStatement.close();
            }

            /** Capturamos excepcion de caracter general*/
            catch (Exception exc) {
                exc.printStackTrace();
                JOptionPane.showMessageDialog(null, GestorIdiomas.getMessage("gestorinscripcion.error"), GestorIdiomas.getMessage("error"), JOptionPane.ERROR_MESSAGE);
            }
        }
    }


    //Fernando
    //Metodo que genera una lista con el TOP de estudiantes inscritos en una Ronda de acuerdo a su puntuacion
    //  y en caso de empate la fecha de realizacion de la prueba.
    //  El TOP  viene definido por los parametros y se refiere al numero maximo de participantes en una ronda
    public List<Usuario> getListaTOPEstudiantesInscritosEnRonda(Ronda ronda){
        List<Usuario> lista = new ArrayList<Usuario>();
        int numeroPersonasMaximoEnFinal = 0;

        //Instanciamos el gestor de parametros para obtener el numero maximo de participantes por prueba
        GestorParametro gestorParametro = new GestorParametro();
        numeroPersonasMaximoEnFinal = gestorParametro.getNumeroPersonasMaximoEnFinal();

        //**Establecemos la sentencia para obtener la lista con los usuarios inscritos a una prueba*/
	String sqlString = null;
	sqlString = "SELECT id_usuario "
                + "FROM "
                + this.schema + "."
                + "inscripcionronda "
                + "WHERE "
                + "id_prueba = ? "
                + "AND "
                + "id_tipo_ronda = ?"
                + "ORDER BY "
                + "puntuacion "
                + "DESC "
                + "LIMIT ?;";

        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

	//**Capturaremos la excepcion en caso de error*/
        try{
            preparedStatement = this.remoto.getConexion().prepareStatement(sqlString);

            preparedStatement.setInt(1, ronda.getId_prueba());
            //Buscamos la lista de las rondas clasificatorias!!!
            preparedStatement.setInt(2, TipoRonda.CLASIFICATORIA.valor());
            preparedStatement.setInt(3, numeroPersonasMaximoEnFinal);

            resultSet = preparedStatement.executeQuery();

            //Recorremos el recordset resultante
            while(resultSet.next()){
                Usuario usuario = new Usuario();

                usuario.setId_usuario(resultSet.getInt("id_usuario"));

                lista.add(usuario);
            }
        }

        /** Capturamos el error en el acceso a la BBDD */
        catch (SQLException exc) {
            exc.printStackTrace();
            JOptionPane.showMessageDialog(null, GestorIdiomas.getMessage("gestorinscripcion.errorBBDD"), GestorIdiomas.getMessage("gestorinscripcion.errorTitulo"), JOptionPane.ERROR_MESSAGE);
        }

        /** Capturamos excepcion de caracter general*/
        catch (Exception exc) {
            exc.printStackTrace();
            JOptionPane.showMessageDialog(null, GestorIdiomas.getMessage("gestorinscripcion.error"), GestorIdiomas.getMessage("gestorinscripcion.errorTitulo"), JOptionPane.ERROR_MESSAGE);
        }

        /** En todo caso ejecutamos el siguiente código*/
        finally {
            //Cerramos las estructuras abiertas
            try {
                resultSet.close();
                preparedStatement.close();
            }

            /** Capturamos excepcion de caracter general*/
            catch (Exception exc) {
                exc.printStackTrace();
                JOptionPane.showMessageDialog(null, GestorIdiomas.getMessage("gestorinscripcion.error"), GestorIdiomas.getMessage("gestorinscripcion.errorTitulo"), JOptionPane.ERROR_MESSAGE);
            }
        }

        //Devolvemos la lista generada
        return lista;
    }


    //Fernando
    //Metodo que asigna valoraciones, puntuacion, a los inscritos en una prueba una vez se ha cerrado
    public void valorarParticipacionEnRonda(Prueba prueba, TipoEstado tipoEstado){
        //Inicializamos variables
        double valorRespuestaAcertada = 0.0;
        double valorRespuestaErronea = 0.0;
        double valorRespuestaNoContestada = 0.0;
        TipoRonda tipoRonda;

        //Instanciamos el gestor de parametros para obtener la puntuacion asignada a cada respuesta
        GestorParametro gestorParametro = new GestorParametro();
        valorRespuestaAcertada = gestorParametro.getPuntuacionPorAcierto();
        valorRespuestaErronea = gestorParametro.getPuntuacionPorError();
        valorRespuestaNoContestada = gestorParametro.getPuntuacionPorNoContestado();

        //Determinamos el tipo de ronda en el quenos encontramos
        if (tipoEstado == TipoEstado.CLASIFICACION_PRELIMINAR){
            tipoRonda = TipoRonda.CLASIFICATORIA;
        }

        else{
            tipoRonda = TipoRonda.ELIMINATORIA;
        }

        Ronda ronda = new Ronda();
        ronda.setId_prueba(prueba.getId_prueba());
        ronda.setId_tipo_ronda(tipoRonda.valor());

        //Variable para recorrer en una lista los uruarios que participacn en una ronda
        List<Usuario> lista = new ArrayList<Usuario>();
        try {
            lista = this.remoto.getListaEstudiantesInscritosEnRonda(ronda);

            //Iteramos por la lista
            for(Usuario usuario: lista){
                //Inicialmente asignamos valor 0 a las respuestas
                double puntuacion = 0.0;
                String respuestaEstudiante;
                String respuestaSolucion;

                //En una cadena obtenemos la solucion de las preguntas
                respuestaSolucion = this.remoto.getRespuestasSolucion(prueba, tipoRonda);
                //En una cadena obtenemos la respuestas del estudiante de las preguntas
                respuestaEstudiante = this.remoto.getRespuestasEstudiantes(ronda, usuario);

                //Verificamos que la cadena de respuestas no sea nula y capturamos la excepcion en caso de que se produzca
                try{
                    char[] cadenaRespuestaEstudiante = respuestaEstudiante.toCharArray();
                    char[] cadenaRespuestaSolucion = respuestaSolucion.toCharArray();

                    //Si no se han rellenado respuetas
                    for(int i=0; i < cadenaRespuestaEstudiante.length ; i++){
                        //Si ha contestado la pregunta evaluamos el resultado
                        if(cadenaRespuestaEstudiante[i]!='0'){
                            if(cadenaRespuestaEstudiante[i]==cadenaRespuestaSolucion[i])
                                puntuacion += valorRespuestaAcertada;
                            else{
                                if(cadenaRespuestaEstudiante[i]!='0')
                                    puntuacion += valorRespuestaErronea;
                            }
                        }

                        //Si no ha contestado la pregunta le asignamos el peso correspondiente
                        else
                            puntuacion += valorRespuestaNoContestada;
                    }
                }

                //Capturamos la excepcion en caso que no haya ningun dato
                catch(NullPointerException exc){
                    puntuacion = 0;
                }

                //Si la puntuacion es negatica, demasiados fallos!!!, la igualamoa a 0
                puntuacion = (puntuacion < 0) ? 0.0 : puntuacion;

                //Hacemos persistencia de la puntuacion
                this.actualizarPuntuacionRonda(ronda, usuario, puntuacion);
            }
        }

        /** Capturamos excepcion de caracter general*/
        catch (Exception exc) {
            exc.printStackTrace();
            JOptionPane.showMessageDialog(null, GestorIdiomas.getMessage("gestorinscripcion.error"), GestorIdiomas.getMessage("gestorinscripcion.errorTitulo"), JOptionPane.ERROR_MESSAGE);
        }
    }


    //Fernando
    //Metodo que hace persistencia de la puntuacion calculada para un estudiante en una ronda
    public void actualizarPuntuacionRonda(Ronda ronda, Usuario usuario, Double puntuacion){
        //Inicializamos las variables a utilizar
	String sqlString = null;
        PreparedStatement preparedStatement = null;

        //Establecemos la sentencia SQL para obtener el conjunto de registros priopuesto
        sqlString = "UPDATE "
                + this.schema + "."
                + "inscripcionronda "
                + "SET "
                + "puntuacion = ? "
                + "WHERE "
                + "id_prueba = ? "
                + "AND "
                + "id_tipo_ronda = ?"
                + "AND "
                + "id_usuario = ?;";

	//Capturaremos la excepcion en caso de error
        try{
            preparedStatement = this.remoto.getConexion().prepareStatement(sqlString);
            preparedStatement.setInt(1, TipoEstado.ANULADO.valor());

            preparedStatement.setDouble(1, puntuacion);
            preparedStatement.setInt(2, ronda.getId_prueba());
            preparedStatement.setInt(3, ronda.getId_tipo_ronda());
            preparedStatement.setInt(4, usuario.getId_usuario());

            preparedStatement.executeUpdate();
        }

        /** Capturamos excepciones asociadas al acceso a la BBDD */
        catch (SQLException exc) {
            exc.printStackTrace();
            JOptionPane.showMessageDialog(null, exc.getMessage(), GestorIdiomas.getMessage("gestorinscripcion.errorTitulo"), JOptionPane.ERROR_MESSAGE);
        }

        /** Capturamos excepciones de caracter general*/
        catch (Exception exc) {
            exc.printStackTrace();
            JOptionPane.showMessageDialog(null, exc.getMessage(), GestorIdiomas.getMessage("gestorinscripcion.errorTitulo"), JOptionPane.ERROR_MESSAGE);
        }

        /** En todo caso ejecutamos el siguiente codigo*/
        finally {
            //Cerramos las estructuras abiertas
            try {
                preparedStatement.close();
            }

            /** Capturamos excepciones de caracter general*/
            catch (Exception exc) {
                exc.printStackTrace();
                JOptionPane.showMessageDialog(null, exc.getMessage(), GestorIdiomas.getMessage("gestorinscripcion.errorTitulo"), JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    //Esteban
    //Metodo para actualizar la inscripcionronda con las respuestas del estudiante
    public boolean guardarRespuestasUsuarios(Usuario usuario, Ronda ronda, String respuestas){
        //Inicializamos las variables a utilizar
	int filasAfectadas = -1;
        String sqlString = null;
        PreparedStatement preparedStatement = null;

	//Establecemos la sentencia para insertar una inscripcionronda
        sqlString = "INSERT INTO "+ this.schema + ".inscripcionronda "
                + "(respuestas_estudiantes,fecha_presentacion,id_usuario,id_prueba,id_tipo_ronda) "
                + "values "
                + "(?,?,?,?,?);";

	//**Capturaremos la excepcion en caso de error */
        try{
            preparedStatement = this.remoto.getConexion().prepareStatement(sqlString);
            preparedStatement.setString(1, respuestas);
            preparedStatement.setDate(2, new java.sql.Date(new Date().getTime()));
            preparedStatement.setInt(3, usuario.getId_usuario());
            preparedStatement.setInt(4, ronda.getId_prueba());
            preparedStatement.setInt(5, ronda.getId_tipo_ronda());

            filasAfectadas = preparedStatement.executeUpdate();
        }

        /** Capturamos excepciones asociadas al acceso a la BBDD */
        catch (SQLException exc) {
            exc.printStackTrace();
            JOptionPane.showMessageDialog(null, GestorIdiomas.getMessage("gestorinscripcion.errorBBDD"), GestorIdiomas.getMessage("gestorinscripcion.errorTitulo"), JOptionPane.ERROR_MESSAGE);
        }

        /** Capturamos excepciones de caracter general*/
        catch (Exception exc) {
            exc.printStackTrace();
            JOptionPane.showMessageDialog(null, GestorIdiomas.getMessage("gestorinscripcion.error"), GestorIdiomas.getMessage("gestorinscripcion.errorTitulo"), JOptionPane.ERROR_MESSAGE);
        }

        /** En todo caso ejecutamos el siguiente codigo*/
        finally {
            //Cerramos las conexiones abiertas
            try {
                preparedStatement.close();
            }

            /** Capturamos excepciones de caracter general*/
            catch (Exception exc) {
                exc.printStackTrace();
                JOptionPane.showMessageDialog(null, GestorIdiomas.getMessage("gestorinscripcion.error"), GestorIdiomas.getMessage("gestorinscripcion.errorTitulo"), JOptionPane.ERROR_MESSAGE);
            }
        }

        return (filasAfectadas > 0);
    }

    //Esteban
    //Metodo para actualizar la inscripcionronda con las respuestas del estudiante
    public boolean haRealizadoRonda(Estudiante estudiante, Ronda ronda){
        //Inicializamos las variables a utilizar
        boolean rondaRealizada = false;

        //**Establecemos la sentencia para obtener la lista con los usuarios inscritos a una prueba*/
	String sqlString = null;
	sqlString = "SELECT * "
                + "FROM "
                + this.schema + "."
                + "inscripcionronda "
                + "WHERE "
                + "id_prueba = ? "
                + "AND "
                + "id_usuario = ? "
                + "AND "
                + "id_tipo_ronda = ?;";

        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

	//**Capturaremos la excepcion en caso de error*/
        try{
            preparedStatement = this.remoto.getConexion().prepareStatement(sqlString);

            preparedStatement.setInt(1, ronda.getId_prueba());
            preparedStatement.setInt(2, estudiante.getId_usuario());
            preparedStatement.setInt(3, ronda.getId_tipo_ronda());
            resultSet = preparedStatement.executeQuery();

            if(resultSet.next())
                rondaRealizada = true;
        }

        /** Capturamos excepciones asociadas al acceso a la BBDD */
        catch (SQLException exc) {
            exc.printStackTrace();
            JOptionPane.showMessageDialog(null, GestorIdiomas.getMessage("gestorinscripcion.errorBBDD"), GestorIdiomas.getMessage("gestorinscripcion.errorTitulo"), JOptionPane.ERROR_MESSAGE);
        }

        /** Capturamos excepciones de caracter general*/
        catch (Exception exc) {
            exc.printStackTrace();
            JOptionPane.showMessageDialog(null, GestorIdiomas.getMessage("gestorinscripcion.error"), GestorIdiomas.getMessage("gestorinscripcion.errorTitulo"), JOptionPane.ERROR_MESSAGE);
        }

        /** En todo caso ejecutamos el siguiente codigo*/
        finally {
            //Cerramos las conexiones abiertas
            try {
                preparedStatement.close();
            }

            /** Capturamos excepciones de caracter general*/
            catch (Exception exc) {
                exc.printStackTrace();
                JOptionPane.showMessageDialog(null, GestorIdiomas.getMessage("gestorinscripcion.error"), GestorIdiomas.getMessage("gestorinscripcion.errorTitulo"), JOptionPane.ERROR_MESSAGE);
            }
        }

        return rondaRealizada;
    }
}
